<script module="three" lang="renderjs">
	// @ts-noCheck
	import * as THREE from 'three';
	import {
		OrbitControls
	} from 'three/examples/jsm/controls/OrbitControls.js';
	import {
		GLTFLoader
	} from 'three/examples/jsm/loaders/GLTFLoader.js';

	import {
		getFile
	} from '@/utils/index';

	export default {
		data() {
			return {
				timer: null,
				scene: '',
				renderer: '',
				xuewei: [],
				xueweihtml: [],
				tagOne: null,
				currXuewei: null,
				loading: 0,
				clipping: -12,
				switchStatus: false,
				camera: '',
				gltf: '',
				animationId: '',
			};
		},
		props: {
			acupoint: {
				type: Array,
				default: () => [],
			},
		},
		mounted() {
			this.threeInit();
		},
		beforeUnmount() {
			cancelAnimationFrame(this.animationId);
		},
		methods: {
			handleAcupoint(newValue) {
				if (newValue) {
					setTimeout(() => {
						let currXuewei = new THREE.MeshStandardMaterial({
							emissive: '#ff0011'
						});
						let DOM = document.getElementById('threeView');
						const to2d = (pos) => {
							let vector = pos.project(this.camera);
							return {
								x: Math.round((0.5 + vector.x / 2) * DOM.offsetWidth),
								y: Math.round((0.5 - vector.y / 2) * DOM.offsetHeight),
							};
						};

						newValue.forEach((item) => {
							let obj = JSON.parse(item.acupointInfo);
							let geometry = new THREE.SphereGeometry(0.04, 50, 50);
							let material = new THREE.MeshBasicMaterial({
								color: 0x00ff00
							});
							let sphere = new THREE.Mesh(geometry, material);
							sphere.position.copy(obj.acupuncturePosition);
							sphere.material = currXuewei;
							sphere.scale.set(2, 2, 2);
							this.scene.add(sphere);
							this.xuewei.push(sphere);
							let element1 = document.getElementById('threeWrap');
							let element = document.createElement('div');
							element.classList.add('tagOne');
							element.id = sphere.id;
							element.innerHTML = item.acupointName;
							element.style.left = to2d(sphere.position.clone()).x + 'px';
							element.style.top = to2d(sphere.position.clone()).y + 'px';
							element1.appendChild(element);
						});
					}, 1000);
				}
			},

			threeInit() {
				// eslint-disable-next-line @typescript-eslint/no-this-alias
				let _this = this;
				let DOM = document.getElementById('threeView');
				let scene = (this.scene = new THREE.Scene());
				const camera = (this.camera = new THREE.PerspectiveCamera(40, DOM.offsetWidth / DOM.offsetHeight, 0.01,
					1000));
				let renderer = new THREE.WebGLRenderer({
					alpha: true,
					// antialias: true,
					// powerPreference: 'low-power'
				});
				renderer.setSize(DOM?.offsetWidth, DOM?.offsetHeight);
				renderer.setPixelRatio(window.devicePixelRatio);
				document.getElementById('threeView').appendChild(renderer.domElement);
				camera.position.x = 0;
				camera.position.y = 0;
				camera.position.z = 35;
				const plane = new THREE.Plane(new THREE.Vector3(0, -1, 0), this.clipping);
				const loader = new GLTFLoader();

				getFile('../../static/body.gltf').then((gltf1) => {
					loader.load(gltf1, (gltf) => {
						_this.gltf = gltf;
						gltf.scene.scale.set(1, 1, 1);
						gltf.scene.position.set(0, 0, 0);
						_this.loading += 1;

						getFile('../../static/matcap.png').then((res) => {
							let textureCap = new THREE.TextureLoader().load(res, () => {
								_this.loading += 1;
								let bodyMat = new THREE.MeshMatcapMaterial({
									matcap: textureCap,
								});

								bodyMat.clippingPlanes = [plane];
								renderer.localClippingEnabled = true;
								gltf.scene.getObjectByName('body').material = bodyMat;
							});
						}).catch(() => {
							console.log('获取文件失败matcap');
						})

						getFile('../../static/dipan.png').then((res) => {
							let textureDipan = new THREE.TextureLoader().load(res, () => {
								_this.loading += 2;
								let dipanMat = new THREE.MeshMatcapMaterial({
									map: textureDipan,
									transparent: true,
									opacity: 0.5,
									side: THREE.DoubleSide,
								});
								gltf.scene.getObjectByName('dipan').material = dipanMat;
							});
						}).catch(() => {
							console.log('获取文件失败dipan');
						})

						scene.add(gltf.scene);
					}, undefined, (error) => {
						console.log('模型加载失败')
					});
				}).catch((ee) => {
					console.log('获取文件失败body');
					uni.showToast({
						title: ee,
						duration: 9000
					})
				})

				const controls = new OrbitControls(camera, renderer.domElement);
				controls.update();
				controls.autoRotate = true;
				controls.enableDamping = true;

				const to2d = (pos) => {
					let vector = pos.project(camera);
					return {
						x: Math.round((0.5 + vector.x / 2) * DOM.offsetWidth),
						y: Math.round((0.5 - vector.y / 2) * DOM.offsetHeight),
					};
				};

				const animate = () => {
					_this.animationId = requestAnimationFrame(animate);
					if (_this.loading === 4) {
						if (_this.clipping < 24) {
							setTimeout(() => {
								_this.clipping += 0.2;
								plane.constant = _this.clipping;
							}, 300);
						}
					}
					controls.update();
					_this.xuewei.length &&
						_this.xuewei.forEach((obj) => {
							let element = document.getElementById(obj.id);
							if (element) {
								element.style.left = to2d(obj.position.clone()).x + 'px';
								element.style.top = to2d(obj.position.clone()).y + 'px';
							}
						});
					renderer.render(scene, camera);
				};
				animate();
			},
		},
	};
</script>

<template>
	<view id="threeWrap" class="uno-w-full uno-h-full uno-relative uno-overflow-hidden">
		<view id="threeView" class="uno-w-full uno-h-full uno-relative" :acupoint="acupoint"
			:change:acupoint="three.handleAcupoint" />
	</view>
</template>

<style lang="scss" scoped>
	.uno-overflow-hidden {
		overflow: hidden;
	}

	.uno-relative {
		position: relative;
	}

	.uno-w-full {
		width: 100%;
	}

	.uno-h-100vh {
		height: 100vh;
	}

	.uno-h-full {
		height: 100%;
	}

	.uno-block {
		display: block;
	}

	.flex-center {
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.uno-items-center {
		align-items: center;
	}

	.uno-flex {
		display: flex;
	}

	.uno-flex-wrap {
		flex-wrap: wrap;
	}

	.uno-justify-between {
		justify-content: space-between;
	}

	.uno-justify-start {
		justify-content: start;
	}

	.uno-mx-auto {
		margin-left: auto;
		margin-right: auto;
	}

	.sm {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background: rgba(255, 255, 255, 1);
		z-index: 999999;

		.sm_inner {
			text-align: center;
			width: 200px;
			position: absolute;
			left: 50%;
			top: 50%;
			transform: translate(-50%, -50%);
		}

		.loading {
			width: 200px;
			background: #ccc;
			height: 3px;

			.inner {
				width: 0;
				height: 100%;
				background: #42b983;
			}
		}

		.tips {
			font-size: 12px;
			font-weight: bold;
			margin-top: 10px;
			color: #666;
		}
	}
</style>